package com.yfs.cloud.commons;

import java.util.HashMap;
import java.util.Map;

import org.springframework.boot.autoconfigure.web.ErrorProperties;
import org.springframework.boot.autoconfigure.web.ResourceProperties;
import org.springframework.boot.autoconfigure.web.reactive.error.DefaultErrorWebExceptionHandler;
import org.springframework.boot.web.reactive.error.ErrorAttributes;
import org.springframework.context.ApplicationContext;
import org.springframework.http.HttpStatus;
import org.springframework.web.reactive.function.server.RequestPredicates;
import org.springframework.web.reactive.function.server.RouterFunction;
import org.springframework.web.reactive.function.server.RouterFunctions;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.reactive.function.server.ServerResponse;
import org.springframework.web.server.ResponseStatusException;

/**
* @Company: 影法師工作室
* @Description: 全局异常处理器, 异常时用JSON代替HTML异常信息
* @author 影法師  
* @date 2020年8月26日 上午10:55:46 
* @version V1.0
 */
public class GlobalExceptionHandler extends DefaultErrorWebExceptionHandler {

	public GlobalExceptionHandler(ErrorAttributes errorAttributes, ResourceProperties resourceProperties,
			ErrorProperties errorProperties, ApplicationContext applicationContext) {
		super(errorAttributes, resourceProperties, errorProperties, applicationContext);
	}

	/**
	 * 获取异常属性 
	 */
	@Override
	protected Map<String, Object> getErrorAttributes(ServerRequest request, boolean includeStackTrace) {
		Throwable error = super.getError(request);
		// 默认是系统异常
		int code = Constants.SYSTEM_ERROR_CODE;
		// 如果网关找不到转发路径
		if (error instanceof ResponseStatusException) {
			switch (((ResponseStatusException) error).getStatus()) {
			case NOT_FOUND:
				code = Constants.NOT_FOUND_CODE;
				break;
			case GATEWAY_TIMEOUT:
				code = Constants.GATEWAY_TIMEOUT_CODE;
				break;
			case BAD_GATEWAY:
				code = Constants.BAD_GATEWAY_CODE;
				break;
			case BAD_REQUEST:
				code = Constants.BAD_REQUEST_CODE;
				break;
			default:
				code = Constants.SYSTEM_ERROR_CODE;
				break;
			}
			// 如果抛出了 jwt 令牌解析的业务异常
		} else if (error instanceof BusinessException) {
			code = ((BusinessException) error).getCode();
		}
		return response(code, this.buildMessage(error));
	}

	/**
	 * 指定响应处理方法为JSON处理的方法
	 */
	@Override
	protected RouterFunction<ServerResponse> getRoutingFunction(ErrorAttributes errorAttributes) {
		return RouterFunctions.route(RequestPredicates.all(), this::renderErrorResponse);
	}

	/**
	 * 根据code获取对应的HttpStatus
	 */
	@Override
	protected HttpStatus getHttpStatus(Map<String, Object> errorAttributes) {
		return HttpStatus.OK;
	}

	/**
	* @Description: 构建异常信息, 也就是 Result 的 msg 属性
	* @author 影法師 
	* @date 2020年8月26日 上午10:57:22 
	* @version V1.0 
	* @param @param request
	* @param @param ex
	* @param @return    
	* @return String    
	* @throws
	 */
	private String buildMessage(Throwable ex) {
		// 如果是业务异常的话
		if (ex instanceof BusinessException) {
			return ((BusinessException) ex).getMsg();
		} else if (ex instanceof ResponseStatusException) {
			switch (((ResponseStatusException) ex).getStatus()) {
			case NOT_FOUND:
				return Constants.NOT_FOUND_MSG;
			case GATEWAY_TIMEOUT:
				return Constants.GATEWAY_TIMEOUT_MSG;
			case BAD_GATEWAY:
				return Constants.BAD_GATEWAY_MSG;
			case BAD_REQUEST:
				return Constants.BAD_REQUEST_MSG;
			default:
				return Constants.SYSTEM_ERROR_MSG;
			}
			// 系统异常
		} else {
			return Constants.SYSTEM_ERROR_MSG;
		}
	}

	/**
	* @Description: 构建返回的JSON数据格式 
	* @author 影法師 
	* @date 2020年8月26日 上午10:57:42 
	* @version V1.0 
	* @param @param status
	* @param @param errorMessage
	* @param @return    
	* @return Map<String,Object>    
	* @throws
	 */
	private static Map<String, Object> response(int code, String errorMessage) {
		Map<String, Object> map = new HashMap<>();
		map.put("code", code);
		map.put("msg", errorMessage);
		map.put("data", null);
		return map;
	}

}